package org.vt.ece3574.pictoslider;

import org.vt.ece3574.pictoslider.menus.GameMenu;
import org.vt.ece3574.pictoslider.menus.Themes;
import org.vt.ece3574.pictoslider.puzzle.Puzzle;
import org.vt.ece3574.pictoslider.puzzle.PuzzleTouchHandler;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

/**
 * This class represents the activity on which all the gameplay will take place.
 * 
 * @author Michael Drescher
 */
public class GameScreen extends Activity {

	// Layout attributes for the puzzle, timer, and start/stop button
	private static final double PUZZLE_LAYOUT_WEIGHT = 0.3;
	private static final int TIMER_LAYOUT_POSITION = 1;
	private static final int COUNTER_LAYOUT_POSITION = 0;
	private static final int PUZZLE_LAYOUT_POSITION = 1;
	private static final double TIMER_LAYOUT_WEIGHT = 0.7;
	private static final int TIMER_TEXT_SIZE = 30;
	private static final int COUNTER_TEXT_SIZE = TIMER_TEXT_SIZE;

	// Keys for values passed to intents
	/**
	 * String Key for long containing the reference time for the timer (time
	 * since epoch).
	 */
	private static final String TIME_RUNNING = "startTime";
	/**
	 * String Key for boolean indicating whether or not the timer is paused
	 */
	private static final String IS_PAUSED = "isPaused";
	/**
	 * String Key used to pass a boolean to the intent. The boolean represents
	 * whether the preview dialog is showing or not.
	 */
	private static final String IS_PREVIEW = "preview";
	/**
	 * Text which appears inside the preview dialog
	 */
	private static final String PREVIEW_DIALOG_TEXT = "Click image to exit";

	/**
	 * String Key for long containing the time it took to solved the puzzle. It
	 * is used to let the Congratulations screen know the time it took to solve
	 * the puzzle.
	 */
	public static final String SOLVE_TIME = "SOLVE_TIME";
	/**
	 * String Key used to pass the number of swaps as an integer to the intent
	 * for this activity. It is also used to let the Congratulations screen know
	 * how many swaps were needed to solve the puzzle.
	 */
	public static final String NUM_SWAPS = "NUM_SWAPS";
	public static final String DIFFICULTY = "DIFFICULTY";

	// Request codes to refer to different activities which were started for
	// results.
	private static final int PAUSE_POP_UP = 0;
	private static final int CONGRATS_POP_UP = 1;

	// References to the timer, counter and puzzle present on the screen.
	private Timer timer;
	private Puzzle puzzle;
	private TextView counter;

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	public void onCreate(Bundle SavedInstanceState) {
		super.onCreate(SavedInstanceState);
		Themes.onActivityCreateSetTheme(this);
		Themes.onActivityCreateSetContentView(this, R.layout.game_screen);

		// Default values
		long startTime = 0;
		boolean isPaused = false;
		boolean isPreview = false;

		// Get the puzzle from the old instance of this activity.
		puzzle = (Puzzle) getLastNonConfigurationInstance();

		// If there was no old instance, initialize the puzzle
		if (puzzle == null) {

			// Get the picture that the user wanted to make into a puzzle using
			// the picture file manager class.
			PictureFileManager pfm = new PictureFileManager(
					getApplicationContext());

			// Get the proper difficulty of the puzzle from Shared Preferences
			int puzzleSize = getSharedPreferences(GameMenu.GAME_PREFS, 0)
					.getInt(GameMenu.DIFFICULTY, 4);

			// Create a new puzzle using the picture stored by pfm
			puzzle = new Puzzle(getApplicationContext(), puzzleSize,
					puzzleSize, pfm.read(), this);

			// Set View parameters for the puzzle
			puzzle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
					LayoutParams.MATCH_PARENT, (float) PUZZLE_LAYOUT_WEIGHT));
		}

		// Give the puzzle a reference to this activity so it can let this
		// activity know when it has been solved.
		puzzle.setParentActivity(this);

		// If from an old instance of GameScreen, retrieve the old value of
		// these variables.
		Bundle b = getIntent().getExtras();
		if (b != null) {
			startTime = b.getLong(TIME_RUNNING);
			isPaused = b.getBoolean(IS_PAUSED);
			isPreview = b.getBoolean(IS_PREVIEW);
		}

		// Initialize the timer
		timer = new Timer(startTime, getApplicationContext());

		// Set View parameters for the timer
		timer.setTextSize(TIMER_TEXT_SIZE);
		timer.setGravity(Gravity.CENTER);
		timer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT, (float) TIMER_LAYOUT_WEIGHT));
		timer.setTextColor(Themes.textColor(this));

		// Initialize the counter
		counter = new TextView(getApplicationContext());

		// Set View parameters for the counter
		counter.setText("" + puzzle.getNumSwaps());
		counter.setTextSize(COUNTER_TEXT_SIZE);
		counter.setGravity(Gravity.CENTER);
		counter.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT, (float) TIMER_LAYOUT_WEIGHT));
		counter.setTextColor(Themes.textColor(this));

		puzzle.setTouchHandler(new PuzzleTouchHandler());

		// Insert the puzzle into the layout
		LinearLayout l = (LinearLayout) findViewById(R.id.toplevel);
		l.addView(puzzle, PUZZLE_LAYOUT_POSITION);

		// Insert the timer and counter into the layout
		l = (LinearLayout) findViewById(R.id.timerCounterLayout);
		l.addView(counter, COUNTER_LAYOUT_POSITION);
		l.addView(timer, TIMER_LAYOUT_POSITION);

		// If the timer was running in a past instance of this activity,
		// make sure it is still running. Otherwise, make sure it is still
		// paused.
		if (!isPaused)
			timer.start();
		else {
			timer.start();
			timer.stop();
		}

		// If the preview Dialog was showing, display it again.
		if (isPreview) {
			picPreview(findViewById(R.id.button3));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onDestroy()
	 * 
	 * Pass the timer base and isPaused to the next instance of this activity.
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();

		// Pass these values on to the next instance of GameScreen.
		getIntent().putExtra(TIME_RUNNING, timer.getTime());
		getIntent().putExtra(IS_PAUSED, !timer.isStarted());

		// Remove puzzle from this LinearLayout so it can be added to the next
		// one.
		LinearLayout l = (LinearLayout) puzzle.getParent();
		l.removeView(puzzle);

		// Reset the stored picture to the defualt picture
		(new PictureFileManager(getApplicationContext())).write(null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onResume()
	 */
	public void onResume() {
		super.onResume();
		// When the activity resumes, start the timer if necessary.
		if (!(timer.isStarted() || puzzle.isSolved()))
			timer.start();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onRetainNonConfigurationInstance()
	 */
	@Override
	public Object onRetainNonConfigurationInstance() {
		// Store the puzzle when the activity is destroyed, so it can be
		// retrieved when the activity is recreated.
		return puzzle;
	}

	/**
	 * Called by puzzle whenever the puzzle has been solved. Updates the high
	 * scores and opens up a Congratulations screen.
	 */
	public void notifyPuzzleSolved() {
		// Stop the timer and update the high scores
		timer.stop();
		Thread t = new Thread(new HighScoreUpdater(getApplicationContext(),
				puzzle.getNumSwaps(), timer.getTime(), puzzle.getBitmap(),
				puzzle.getDifficulty()));
		t.start();

		// Launch the Congratulations Pop Up
		startActivityForResult(
				new Intent(this, CongratulationsPopUpWindow.class)
						.putExtra(SOLVE_TIME, timer.getTime())
						.putExtra(NUM_SWAPS, puzzle.getNumSwaps())
						.putExtra(DIFFICULTY, puzzle.getDifficulty().asString()),
				CONGRATS_POP_UP);
	}

	/**
	 * Button Click Handler for the pause button. Brings up a pause window,
	 * which allows the user to either resume or quit the game.
	 * 
	 * @author Michael Drescher
	 * @param v
	 *            - The view which was clicked
	 */
	public void pauseTimer(View v) {
		timer.stop();
		startActivityForResult(new Intent(getApplicationContext(),
				PausePopUpWindow.class), PAUSE_POP_UP);
	}

	/**
	 * OnClickListener for the Solve Now button (For testing only)
	 * 
	 * @param v
	 *            - The view which was clicked.
	 */
	public void solveNow(View v) {
		notifyPuzzleSolved();
	}

	/**
	 * Updates the displayed counter whenever a swap occurs in the puzzle.
	 */
	public void notifySwapped() {
		counter.setText("" + puzzle.getNumSwaps());
	}

	/**
	 * OnClickListener for the Preview Button. This method pauses the timer and
	 * launches a dialog window that allows the user to see what the completed
	 * puzzle should look like.
	 * 
	 * @param v
	 */
	public void picPreview(View v) {

		// Stop timer if necessary
		if (timer.isStarted())
			timer.stop();

		// Let activity know that the dialog is showing.
		getIntent().putExtra(IS_PREVIEW, true);

		// Set up the Dialog Parameters
		final Dialog d = new Dialog(this);
		d.setOwnerActivity(this);
		d.requestWindowFeature(Window.FEATURE_NO_TITLE);
		d.setOnCancelListener(new OnCancelListener() {
			// If cancelled, dismiss the dialog, restart the timer, and notify
			// the activity
			public void onCancel(DialogInterface arg0) {
				d.dismiss();
				timer.start();
				d.getOwnerActivity().getIntent().putExtra(IS_PREVIEW, false);
			}
		});

		// Set up the ImageView that appears in the dialog with a preview of the
		// puzzle
		ImageView i = new ImageView(this);
		i.setOnClickListener(new OnClickListener() {
			// Treat a click of this ImageView just like a cancel for the dialog
			public void onClick(View v) {
				d.dismiss();
				timer.start();
				d.getOwnerActivity().getIntent().putExtra(IS_PREVIEW, false);
			}
		});
		i.setImageBitmap(puzzle.getBitmap());

		// Set up the TextView which appears in the Dialog
		TextView tv = new TextView(this);
		tv.setGravity(Gravity.CENTER);
		tv.setText(PREVIEW_DIALOG_TEXT);
		tv.setTextColor(Themes.textColor(this));

		// Add the ImageView and the TextView to a LinearLayout, and set the
		// Layout's Parameters
		LinearLayout ll = new LinearLayout(this);
		ll.setOrientation(LinearLayout.VERTICAL);
		ll.addView(tv);
		ll.addView(i);
		Themes.setBackgroundColor(this, ll);

		// Put the LinearLayout inside the Dialog, and display the dialog.
		d.setContentView(ll);
		d.show();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onActivityResult(int, int,
	 * android.content.Intent)
	 */
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent i) {
		super.onActivityResult(requestCode, resultCode, i);

		// Determine the activity which just delivered a result, and act
		// appropriately.
		switch (requestCode) {
		case PAUSE_POP_UP:
			timer.start();
			if (resultCode == RESULT_OK) {
				if (i.getExtras().getBoolean(PausePopUpWindow.QUIT)) {
					this.finish();
				}
			}
			break;

		case CONGRATS_POP_UP:
			if (resultCode == RESULT_OK) {
				this.finish();
			}
		}
	}
}
